const { AdView, User, PointsTransaction, sequelize } = require('../models')
const pointsService = require('./pointsService')
const AntiCheatService = require('./antiCheatService')
const logger = require('../utils/logger')
const { Op } = require('sequelize')

class AdService {
  /**
   * 获取广告配置
   */
  static getAdConfig() {
    return {
      // 小程序广告配置
      miniprogram: {
        adUnitIds: {
          rewardedVideo: process.env.WECHAT_AD_REWARDED_VIDEO_ID || 'adunit-rewardedvideo',
          banner: process.env.WECHAT_AD_BANNER_ID || 'adunit-banner',
          interstitial: process.env.WECHAT_AD_INTERSTITIAL_ID || 'adunit-interstitial'
        }
      },
      // H5广告配置
      h5: {
        platforms: {
          gdt: {
            name: '腾讯广点通',
            appId: process.env.GDT_APP_ID || 'your-gdt-app-id',
            adUnitIds: {
              rewardedVideo: process.env.GDT_REWARDED_VIDEO_ID || 'your-rewarded-video-id',
              banner: process.env.GDT_BANNER_ID || 'your-banner-id',
              interstitial: process.env.GDT_INTERSTITIAL_ID || 'your-interstitial-id'
            }
          },
          baidu: {
            name: '百度联盟',
            appId: process.env.BAIDU_APP_ID || 'your-baidu-app-id',
            adUnitIds: {
              rewardedVideo: process.env.BAIDU_REWARDED_VIDEO_ID || 'your-rewarded-video-id',
              banner: process.env.BAIDU_BANNER_ID || 'your-banner-id',
              interstitial: process.env.BAIDU_INTERSTITIAL_ID || 'your-interstitial-id'
            }
          },
          bytedance: {
            name: '字节跳动穿山甲',
            appId: process.env.BYTEDANCE_APP_ID || 'your-bytedance-app-id',
            adUnitIds: {
              rewardedVideo: process.env.BYTEDANCE_REWARDED_VIDEO_ID || 'your-rewarded-video-id',
              banner: process.env.BYTEDANCE_BANNER_ID || 'your-banner-id',
              interstitial: process.env.BYTEDANCE_INTERSTITIAL_ID || 'your-interstitial-id'
            }
          }
        },
        defaultPlatform: process.env.H5_AD_PLATFORM || 'gdt'
      },
      // 通用配置
      rewardRules: {
        video_15_30: 0.5,  // 15-30秒视频奖励
        video_30_60: 1.0,  // 30-60秒视频奖励
        interactive: 1.5   // 互动广告奖励
      },
      dailyLimit: 50,
      minViewDuration: 15, // 最小观看时长（秒）
      maxViewsPerIP: 100,  // 每IP每日最大观看次数
      minIntervalSeconds: 30 // 最小观看间隔（秒）
    }
  }

  /**
   * 获取用户今日观看限制信息
   * @param {number} userId - 用户ID
   * @returns {Object} 限制信息
   */
  static async getUserAdLimit(userId) {
    const today = new Date()
    today.setHours(0, 0, 0, 0)
    const tomorrow = new Date(today)
    tomorrow.setDate(tomorrow.getDate() + 1)
    
    const todayViews = await AdView.findAll({
      where: {
        user_id: userId,
        created_at: {
          [Op.between]: [today, tomorrow]
        }
      }
    })
    
    const todayCount = todayViews.length
    const completedCount = todayViews.filter(view => view.is_completed).length
    const dailyLimit = this.getAdConfig().dailyLimit
    const canWatch = todayCount < dailyLimit
    
    // 计算今日获得积分
    const todayEarned = todayViews
      .filter(view => view.is_completed)
      .reduce((sum, view) => sum + parseFloat(view.points_rewarded), 0)
    
    return {
      todayCount,
      completedCount,
      dailyLimit,
      canWatch,
      todayEarned,
      nextResetTime: tomorrow,
      rewardPoints: canWatch ? 1 : 0
    }
  }

  /**
   * 验证广告观看的有效性
   * @param {number} userId - 用户ID
   * @param {Object} adInfo - 广告信息
   * @param {string} ipAddress - IP地址
   * @param {string} userAgent - 用户代理
   * @returns {Object} 验证结果
   */
  static async validateAdView(userId, adInfo, ipAddress, userAgent) {
    try {
      // 使用防刷服务进行全面验证
      const validation = await AntiCheatService.validateAdView(
        userId,
        adInfo,
        ipAddress,
        userAgent
      )
      
      // 如果验证失败，记录可疑活动
      if (!validation.valid) {
        await AntiCheatService.recordSuspiciousActivity({
          userId,
          ipAddress,
          userAgent,
          activityType: 'invalid_ad_view',
          riskLevel: validation.riskLevel || 'medium',
          reason: validation.reason,
          metadata: {
            adType: adInfo.adType,
            platform: adInfo.platform,
            timestamp: adInfo.timestamp
          }
        })
      }
      
      return validation
    } catch (error) {
      logger.error('验证广告观看失败:', error)
      return { valid: false, reason: '验证失败' }
    }
  }

  /**
   * 记录广告观看
   * @param {number} userId - 用户ID
   * @param {Object} adData - 广告数据
   * @param {string} ipAddress - IP地址
   * @param {string} userAgent - 用户代理
   * @returns {Object} 观看记录
   */
  static async recordAdView(userId, adData, ipAddress, userAgent) {
    const {
      adType,
      adUnitId,
      platform,
      viewDuration,
      isCompleted,
      timestamp
    } = adData
    
    // 防刷验证
    const validation = await this.validateAdView(userId, {
      adType,
      platform,
      timestamp
    }, ipAddress, userAgent)
    
    if (!validation.valid) {
      throw new Error(validation.reason)
    }
    
    // 创建观看记录
    const adView = await AdView.create({
      user_id: userId,
      ad_id: adUnitId,
      ad_type: adType,
      ad_source: 'wechat',
      platform,
      view_duration: viewDuration || 0,
      is_completed: isCompleted ? 1 : 0,
      points_rewarded: 0, // 先记录为0，奖励在reward方法中发放
      ip_address: ipAddress,
      user_agent: userAgent
    })
    
    logger.info(`用户 ${userId} 观看广告记录创建成功`, {
      adViewId: adView.id,
      adType,
      platform,
      isCompleted
    })
    
    return adView
  }

  /**
   * 发放广告奖励
   * @param {number} userId - 用户ID
   * @param {Object} rewardData - 奖励数据
   * @returns {Object} 奖励结果
   */
  static async rewardAdPoints(userId, rewardData) {
    const {
      adType,
      adUnitId,
      platform,
      timestamp
    } = rewardData
    
    // 查找对应的观看记录
    const adView = await AdView.findOne({
      where: {
        user_id: userId,
        ad_id: adUnitId,
        ad_type: adType,
        platform,
        is_completed: 1,
        points_rewarded: 0, // 未发放奖励的记录
        created_at: {
          [Op.gte]: new Date(timestamp - 60000), // 允许1分钟误差
          [Op.lte]: new Date(timestamp + 60000)
        }
      },
      order: [['created_at', 'DESC']]
    })
    
    if (!adView) {
      throw new Error('未找到有效的观看记录')
    }
    
    // 检查今日奖励次数限制
    const today = new Date()
    today.setHours(0, 0, 0, 0)
    const tomorrow = new Date(today)
    tomorrow.setDate(tomorrow.getDate() + 1)
    
    const todayRewardedCount = await AdView.count({
      where: {
        user_id: userId,
        is_completed: 1,
        points_rewarded: {
          [Op.gt]: 0
        },
        created_at: {
          [Op.between]: [today, tomorrow]
        }
      }
    })
    
    const config = this.getAdConfig()
    if (todayRewardedCount >= config.dailyLimit) {
      throw new Error('今日观看次数已达上限')
    }
    
    // 计算奖励积分
    const rewardPoints = this.calculateRewardPoints(adType, adView.view_duration)
    
    if (rewardPoints <= 0) {
      throw new Error('观看时长不足，无法获得奖励')
    }
    
    // 使用事务确保数据一致性
    const transaction = await sequelize.transaction()
    
    try {
      // 发放积分奖励
      const pointRecord = await pointsService.awardPoints(
        userId,
        rewardPoints,
        'ad_watch',
        adView.id,
        `观看${adType}广告奖励`,
        { transaction }
      )
      
      // 更新观看记录的奖励积分
      await adView.update({
        points_rewarded: rewardPoints
      }, { transaction })
      
      await transaction.commit()
      
      logger.info(`用户 ${userId} 获得广告奖励`, {
        adViewId: adView.id,
        rewardPoints,
        pointRecordId: pointRecord.id
      })
      
      return {
        points: rewardPoints,
        pointRecordId: pointRecord.id,
        message: `恭喜获得 ${rewardPoints} 积分！`
      }
    } catch (error) {
      await transaction.rollback()
      throw error
    }
  }

  /**
   * 计算奖励积分
   * @param {string} adType - 广告类型
   * @param {number} viewDuration - 观看时长
   * @returns {number} 奖励积分
   */
  static calculateRewardPoints(adType, viewDuration) {
    const config = this.getAdConfig()
    
    if (adType === 'video') {
      if (viewDuration >= 15 && viewDuration < 30) {
        return config.rewardRules.video_15_30
      } else if (viewDuration >= 30) {
        return config.rewardRules.video_30_60
      }
    } else if (adType === 'interactive') {
      return config.rewardRules.interactive
    }
    
    // 其他类型默认奖励
    return 0.5
  }

  /**
   * 生成设备指纹（简单实现）
   * @param {Object} adInfo - 广告信息
   * @returns {string} 设备指纹
   */
  static generateDeviceFingerprint(adInfo) {
    const { userAgent, ipAddress, platform } = adInfo
    const crypto = require('crypto')
    
    const fingerprint = crypto
      .createHash('md5')
      .update(`${userAgent}-${ipAddress}-${platform}`)
      .digest('hex')
    
    return fingerprint
  }

  /**
   * 获取广告统计数据
   * @param {Object} filters - 过滤条件
   * @returns {Object} 统计数据
   */
  static async getAdStatistics(filters = {}) {
    const {
      startDate,
      endDate,
      adType,
      platform,
      userId
    } = filters
    
    // 构建查询条件
    const whereCondition = {}
    
    if (startDate && endDate) {
      whereCondition.created_at = {
        [Op.between]: [new Date(startDate), new Date(endDate)]
      }
    }
    
    if (adType) {
      whereCondition.ad_type = adType
    }
    
    if (platform) {
      whereCondition.platform = platform
    }
    
    if (userId) {
      whereCondition.user_id = userId
    }
    
    // 获取基础统计数据
    const totalViews = await AdView.count({ where: whereCondition })
    const completedViews = await AdView.count({
      where: { ...whereCondition, is_completed: 1 }
    })
    
    const totalRewards = await AdView.sum('points_rewarded', { where: whereCondition })
    
    // 按日期分组统计
    const dailyStats = await AdView.findAll({
      attributes: [
        [sequelize.fn('DATE', sequelize.col('created_at')), 'date'],
        [sequelize.fn('COUNT', sequelize.col('id')), 'views'],
        [sequelize.fn('SUM', sequelize.col('is_completed')), 'completed'],
        [sequelize.fn('SUM', sequelize.col('points_rewarded')), 'rewards']
      ],
      where: whereCondition,
      group: [sequelize.fn('DATE', sequelize.col('created_at'))],
      order: [[sequelize.fn('DATE', sequelize.col('created_at')), 'DESC']],
      raw: true
    })
    
    // 按广告类型分组统计
    const typeStats = await AdView.findAll({
      attributes: [
        'ad_type',
        [sequelize.fn('COUNT', sequelize.col('id')), 'views'],
        [sequelize.fn('SUM', sequelize.col('is_completed')), 'completed'],
        [sequelize.fn('SUM', sequelize.col('points_rewarded')), 'rewards']
      ],
      where: whereCondition,
      group: ['ad_type'],
      raw: true
    })
    
    return {
      summary: {
        totalViews,
        completedViews,
        completionRate: totalViews > 0 ? (completedViews / totalViews * 100).toFixed(2) : 0,
        totalRewards: parseFloat(totalRewards || 0)
      },
      dailyStats,
      typeStats
    }
  }

  /**
   * 清理过期的广告观看记录
   * @param {number} daysToKeep - 保留天数
   * @returns {number} 清理的记录数
   */
  static async cleanupOldAdViews(daysToKeep = 90) {
    const cutoffDate = new Date()
    cutoffDate.setDate(cutoffDate.getDate() - daysToKeep)
    
    const deletedCount = await AdView.destroy({
      where: {
        created_at: {
          [Op.lt]: cutoffDate
        }
      }
    })
    
    logger.info(`清理了 ${deletedCount} 条过期广告观看记录`)
    return deletedCount
  }
}

module.exports = AdService